package com.onpositive.wikistorage;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import com.onpositive.mediawiki.propertyparser.ParsedCategory;
import com.onpositive.mediawiki.propertyparser.ParsedDocument;

public class CategoryLinksExtractor {
	
public static void extractLinks( ParsedCategory category ) {
		
		HashMap<String,HashMap<String,HashMap<String,Integer>>> refStatMap = new HashMap<String, HashMap<String,HashMap<String,Integer>>>() ;
		HashMap<String,HashMap<String,HashMap<String,Integer>>> capStatMap = new HashMap<String, HashMap<String,HashMap<String,Integer>>>() ;
		
		HashMap<String,HashMap<String,Integer>> refCases = new HashMap<String, HashMap<String,Integer>>() ;
		HashMap<String,HashMap<String,Integer>> capCases = new HashMap<String, HashMap<String,Integer>>() ;
		
		for( ParsedDocument pd : category.getDocumentsList() ){
			HashMap<String,ArrayList<String>> ownLinks = pd.getOwnLinks() ;
			
			for( Map.Entry<String, ArrayList<String>> entry : ownLinks.entrySet() ) {
				
				String propName = entry.getKey() ;
				ArrayList<String> refsAndCaps = entry.getValue() ;
				
				if( propName == null || propName.trim().length() == 0 )
					continue ;
				
				if( refsAndCaps.isEmpty() )
					continue ;
				
				int totalCount = refsAndCaps.size();
				ArrayList<String> capsAndRefs = new ArrayList<String>( totalCount ) ;
				for( int i = 0 ; i < totalCount ; i++ )
					capsAndRefs.add(null) ;				
				
				for( int i = 0 ; i < totalCount ; i+=2 ){
					capsAndRefs.set(  i , refsAndCaps.get(i+1) ) ;
					capsAndRefs.set( i+1, refsAndCaps.get( i ) ) ;
				}
				
				contributeValues( propName, refStatMap, refsAndCaps ) ;
				contributeValues( propName, capStatMap, capsAndRefs ) ;
				
				contributeCaseInfo( refCases, refsAndCaps ) ;
				contributeCaseInfo( capCases, capsAndRefs ) ;
			}			
		}
		
		LinkStorage newRefs = createLinkStorage( category.getRefs().getTitle(), refStatMap, refCases ) ;
		LinkStorage newCaptions = createLinkStorage( category.getCaptions().getTitle(), capStatMap, capCases ) ;
		
		refineCases( newRefs    , newCaptions ) ;
		refineCases( newCaptions, newRefs     ) ;
		
		newCaptions.setFirstLetterToUpperCase() ;
		
		category.setRefs( newRefs ) ;
		category.setCaptions( newCaptions ) ;
	}

	static private void refineCases( LinkStorage caseProvider, LinkStorage valueHolder )
	{
		ArrayList<String> lst = new ArrayList<String>() ;
		for( Map.Entry<String, HashMap<String, String>> entry : valueHolder.perPropertyStorage.entrySet() ){
			
			String propName = entry.getKey() ;
			if( propName == null || propName.trim().length() == 0 )
				continue;
			
			HashMap<String, String> propStatMap = entry.getValue() ;			
			if( propStatMap.isEmpty() )
				continue ;
			
			lst.clear() ;
			for( Map.Entry<String, String> e : propStatMap.entrySet() )
			{				
				String value = e.getValue() ;
				if( value == null )
					continue ;
				
				String bestCase = caseProvider.getBestCase(value) ;
				if( value.equals(bestCase) )
					continue ;
				
				String key = e.getKey() ;
				lst.add(key) ;
				lst.add(value) ;
			}
			
			int size = lst.size();
			for( int i = 0 ; i < size ; i+=2 ){
				String key = lst.get(i) ;
				String value = lst.get(i+1) ;
				propStatMap.put(key, value) ;
			}			
		}
	}

	static private LinkStorage createLinkStorage(
			String title,
			HashMap<String, HashMap<String, HashMap<String, Integer>>> statMap,
			HashMap<String, HashMap<String, Integer>> caseMap )
	{		
		LinkStorage result = new LinkStorage(title) ;
		
		for( Map.Entry<String, HashMap<String, HashMap<String, Integer>>> entry : statMap.entrySet() ){
			
			String propName = entry.getKey() ;
			if( propName == null || propName.trim().length() == 0 )
				continue;
			
			HashMap<String, HashMap<String, Integer>> propStatMap = entry.getValue() ;			
			if( propStatMap.isEmpty() )
				continue ;
			
			HashMap<String,String> propMap = result.getPropertyMapForCompletion(propName) ;
			
			for( Map.Entry<String, HashMap<String, Integer>> e : propStatMap.entrySet() ){
				
				String value = e.getKey() ;
				if( value == null || value.trim().length() == 0 )
					continue ;
				
				HashMap<String, Integer> valStatMap = e.getValue() ;
				if( valStatMap.size() == 0 ){
					propMap.put(value, null) ;
					continue ;
				}
				
				String bestCoValue = null ;
				int maxWeight = 0 ;
				for( Map.Entry<String,Integer> en : valStatMap.entrySet() ){
					String coValue = en.getKey() ;
					if( coValue == null || coValue.trim().length() == 0 )
						continue ;
						
					Integer weight = en.getValue() ;
					if( weight > maxWeight ){
						bestCoValue = coValue ;
						maxWeight = weight ;
					}					
				}
				propMap.put(value, bestCoValue ) ;
			}			
		}
		
		HashMap<String,String> caseResolver = result.getCaseResolver() ;
		
		for( Map.Entry<String, HashMap<String, Integer>> e : caseMap.entrySet() ){
			
			String value = e.getKey() ;
			if( value == null || value.trim().length() == 0 )
				continue ;
			
			HashMap<String, Integer> valStatMap = e.getValue() ;
			if( valStatMap.size() == 0 ){
				caseResolver.put(value, value) ;
				continue ;
			}
			
			String bestCase = null ;
			int maxWeight = 0 ;
			for( Map.Entry<String,Integer> en : valStatMap.entrySet() ){
				String caseOccurance = en.getKey() ;
				if( caseOccurance == null || caseOccurance.trim().length() == 0 )
					continue ;
					
				Integer weight = en.getValue() ;
				if( weight > maxWeight ){
					bestCase = caseOccurance ;
					maxWeight = weight ;
				}					
			}
			caseResolver.put(value, bestCase ) ;
		}
		
		return result;
	}
	
	static private void contributeValues(
			String propName,
			HashMap<String, HashMap<String, HashMap<String, Integer>>> statMap,
			ArrayList<String> valPairs )
	{
		HashMap<String, HashMap<String, Integer>> propMap = statMap.get(propName) ;
		if( propMap == null ){
			propMap = new HashMap<String, HashMap<String,Integer>>() ;
			statMap.put(propName, propMap) ;
		}
		
		int size = valPairs.size() ;
		for( int i = 0 ; i < size ; i+=2 ){
			
			String value = valPairs.get(i) ;
			if( value == null || value.length() == 0 )
				continue ;
			
			value = LinkStorage.canonizeKeyString(value); 
			String coValue = valPairs.get(i+1) ;
			
			HashMap<String,Integer> valMap = propMap.get(value) ;
			if( valMap == null ){
				valMap = new HashMap<String, Integer>() ;
				propMap.put(value, valMap) ;
			}
			Integer count = valMap.get(coValue) ;
			count = count != null ? count + 1 : 1 ;
			valMap.put(coValue, count) ;			
		}		
	}
	
	static private void contributeCaseInfo(
			HashMap<String, HashMap<String, Integer>> casesMap,
			ArrayList<String> valPairs )
	{
		int size = valPairs.size() ;
		for( int i = 0 ; i < size ; i+=2 ){
			
			String value = valPairs.get(i) ;
			if( value == null )
				continue ;
			
			value = LinkStorage.canonizeKeyString(value);
			String caseOccurance = value.replace('_', ' ') ;
			
			HashMap<String,Integer> valMap = casesMap.get(value) ;
			if( valMap == null ){
				valMap = new HashMap<String, Integer>() ;
				casesMap.put(value, valMap) ;
			}
			Integer count = valMap.get(caseOccurance) ;
			count = count != null ? count + 1 : 1 ;
			valMap.put(caseOccurance, count) ;			
		}		
	}

	

}
